using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

using NBear.Common;

namespace NBear.IoC.Service
{
    public class BaseServiceInterfaceImpl
    {
        public static int DefaultExpireMinutes = 30;
        public static EntitySerializer DefaultEntitySerializer = new EntitySerializer(EntitySerializeType.Json);

        private IServiceContainer container;
        private Type serviceInterfaceType;

        public BaseServiceInterfaceImpl(IServiceContainer container, Type serviceInterfaceType)
        {
            this.container = container;
            this.serviceInterfaceType = serviceInterfaceType;
        }

        protected object CallService(string subServiceName, Type returnType, params object[] paramValues)
        {
            object errorReturnValue = Util.DefaultValue(returnType);

            RequestMessage reqMsg = new RequestMessage();
            reqMsg.Expiration = DateTime.Now.AddMinutes(DefaultExpireMinutes);
            reqMsg.MessageId = Guid.NewGuid();
            reqMsg.ServiceName = serviceInterfaceType.FullName;
            reqMsg.SubServiceName = subServiceName;
            reqMsg.Timestamp = DateTime.Now;
            reqMsg.TransactionId = Guid.NewGuid();

            MethodInfo mi = serviceInterfaceType.GetMethod(subServiceName);

            if (mi == null)
            {
                return errorReturnValue;
            }

            ParameterInfo[] pis = mi.GetParameters();

            if ((pis.Length == 0 && paramValues != null && paramValues.Length > 0) || (paramValues != null && pis.Length != paramValues.Length))
            {
                return errorReturnValue;
            }

            if (pis.Length > 0)
            {
                for (int i = 0; i < paramValues.Length; i++)
                {
                    if (paramValues[i] == null)
                    {
                        continue;
                    }

                    string val;

                    if (typeof(IEntity).IsAssignableFrom(pis[i].ParameterType))
                    {
                        val = DefaultEntitySerializer.Serialize(paramValues[i]);
                    }
                    else if (typeof(IEntity[]).IsAssignableFrom(pis[i].ParameterType))
                    {
                        val = DefaultEntitySerializer.SerializeArray((Array)paramValues[i]);
                    }
                    else
                    {
                        val = SerializeHelper.Serialize(paramValues[i]);
                    }

                    reqMsg.Parameters[pis[i].Name] = val;
                }
            }

            ResponseMessage resMsg = container.CallService(serviceInterfaceType.FullName, reqMsg);

            if (resMsg == null)
            {
                return errorReturnValue;
            }

            try
            {
                if (returnType == typeof(System.Data.DataSet))
                {
                    return resMsg.Data;
                }
                else if (typeof(IEntity).IsAssignableFrom(returnType))
                {
                    return typeof(EntitySerializer).GetMethod("Deserialize").MakeGenericMethod(returnType).Invoke(DefaultEntitySerializer, new object[] { resMsg.Text });
                }
                else if (typeof(IEntity[]).IsAssignableFrom(returnType))
                {
                    return typeof(EntitySerializer).GetMethod("DeserializeArray").MakeGenericMethod(Util.GetOriginalTypeOfArrayType(returnType)).Invoke(DefaultEntitySerializer, new object[] { resMsg.Text });
                }
                else if (resMsg.Text != null)
                {
                    return SerializeHelper.Deserialize(returnType, resMsg.Text);
                }
            }
            catch
            {
            }

            return errorReturnValue;
        }
    }
}
